using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using SevenWizards1.SpriteClasses;

namespace SevenWizards1.CoreComponents
{
    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    public class TileEngine : Microsoft.Xna.Framework.DrawableGameComponent
    {
        SpriteBatch spriteBatch;
        static Texture2D tileset;

        static Rectangle[] tiles = new Rectangle[4];

        KeyboardState oldState;
        KeyboardState newState;

        TileMap map;

        List<GameComponent> childComponents = new List<GameComponent>();

        static int tileWidth = 64;
        static int tileHeight = 48;

        static int tileMapWidth;
        static int tileMapHeight;

        static int screenWidth;
        static int screenHeight;

        static int mapWidthInPixels;
        static int mapHeightInPixels;

        static float cameraX;
        static float cameraY;

        Random random = new Random();
        Camera camera = new Camera();

        ContentManager Content;

        public TileEngine(Game game, Texture2D tileset, int tileMapWidth, int tileMapHeight)
            : base(game)
        {
            map = new TileMap(tileMapWidth, tileMapHeight, game);
            childComponents.Add(map);

            spriteBatch =
                (SpriteBatch)Game.Services.GetService(typeof(SpriteBatch));

            TileEngine.tileset = tileset;
            TileEngine.tileMapWidth = tileMapWidth;
            TileEngine.tileMapHeight = tileMapHeight;

            tiles[0] = new Rectangle(0, 0, 128, 128);
            tiles[1] = new Rectangle(128, 0, 128, 128);
            tiles[2] = new Rectangle(0, 128, 128, 128);
            tiles[3] = new Rectangle(128, 128, 128, 128);

            Content =
                (ContentManager)Game.Services.GetService(typeof(ContentManager));

            Texture2D chest = Content.Load<Texture2D>(@"Items\chest");

            ItemSprite tempItemSprite;
            Vector2 position;
            Random random = new Random();

            for (int i = 0; i < 10; i++)
            {
                position = new Vector2(
                    random.Next(0, 10),
                    random.Next(0, 10));
                
                tempItemSprite = new ItemSprite(game,
                    chest, position);
                
                childComponents.Add(tempItemSprite);
            }

            screenWidth = game.Window.ClientBounds.Width;
            screenHeight = game.Window.ClientBounds.Height;
        }

        public static int TileMapWidth
        {
            get { return tileMapWidth; }
        }

        public static int TileMapHeight
        {
            get { return tileMapHeight; }
        }

        public static int TileWidth
        {
            get { return tileWidth; }
        }

        public static int TileHeight
        {
            get { return tileHeight; }
        }

        public static int ScreenWidth
        {
            get { return screenWidth; }
        }

        public static int ScreenHeight
        {
            get { return screenHeight; }
        }

        public static int MapWidthInPixels
        {
            get { return mapWidthInPixels; }
        }

        public static int MapHeightInPixels
        {
            get { return mapHeightInPixels; }
        }

        public static int CameraXPosition
        {
            get { return (int)cameraX; }
        }

        public static int CameraYPositon
        {
            get { return (int)cameraY; }
        }

        public static Texture2D TileSet
        {
            get { return tileset; }
        }

        public static Rectangle[] Tiles
        {
            get { return tiles; }
        }

        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public override void Initialize()
        {
            // TODO: Add your initialization code here

            base.Initialize();
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            base.Update(gameTime);

            mapWidthInPixels = tileMapWidth * tileWidth;
            mapHeightInPixels = tileMapHeight * tileHeight;

            newState = Keyboard.GetState();
            Vector2 motion = new Vector2();

            if (newState.IsKeyDown(Keys.Escape))
            {
                Game.Exit();
            }

            if (newState.IsKeyDown(Keys.Up) || newState.IsKeyDown(Keys.NumPad8))
            {
                motion.Y--;
            }

            if (newState.IsKeyDown(Keys.Right) || newState.IsKeyDown(Keys.NumPad6))
            {
                motion.X++;
            }

            if (newState.IsKeyDown(Keys.Down) || newState.IsKeyDown(Keys.NumPad2))
            {
                motion.Y++;
            }

            if (newState.IsKeyDown(Keys.Left) || newState.IsKeyDown(Keys.NumPad4))
            {
                motion.X--;
            }

            if (newState.IsKeyDown(Keys.NumPad9))
            {
                motion.X++;
                motion.Y--;
            }

            if (newState.IsKeyDown(Keys.NumPad3))
            {
                motion.X++;
                motion.Y++;
            }

            if (newState.IsKeyDown(Keys.NumPad1))
            {
                motion.X--;
                motion.Y++;
            }

            if (newState.IsKeyDown(Keys.NumPad7))
            {
                motion.X--;
                motion.Y--;
            }

            if (motion != Vector2.Zero)
            {
                motion.Normalize();
            }

            camera.Position += motion * camera.Speed;

            camera.LockCamera();
            TileEngine.cameraX = camera.Position.X;
            TileEngine.cameraY = camera.Position.Y;
            
            oldState = newState;
        }

        public override void Draw(GameTime gameTime)
        {
            foreach (GameComponent child in childComponents)
            {
                if ((child is DrawableGameComponent) && ((DrawableGameComponent)child).Visible)
                {
                    ((DrawableGameComponent)child).Draw(gameTime);
                }
            }
            base.Draw(gameTime);
        }

        public virtual void Show()
        {
            Enabled = true;
            Visible = true;
            foreach (GameComponent child in childComponents)
            {
                child.Enabled = true;
                if ((child is DrawableGameComponent))
                    ((DrawableGameComponent)child).Visible = true;
            }
        }

        public virtual void Hide()
        {
            Enabled = false;
            Visible = false;
            foreach (GameComponent child in childComponents)
            {
                child.Enabled = false;
                if ((child is DrawableGameComponent))
                    ((DrawableGameComponent)child).Visible = false;
            }
        }

        public virtual void Pause()
        {
            Enabled = !Enabled;
            foreach (GameComponent child in childComponents)
            {
                child.Enabled = false;
                if ((child is DrawableGameComponent))
                    ((DrawableGameComponent)child).Visible = false;
            }
        }
    }
}